#pragma once

#include <stdio.h>
#include <iostream>
#include <SFML\Graphics.hpp>


#define M_PI 3.1415f
#define LIGHT_RADIUS 100.f
#define LIGHT_FOCAL_ANGLE_RAD (M_PI*0.5f)

void Execute()
{
	sf::RenderWindow window(sf::VideoMode(800, 600), "POC perfect shadow");
	//window.setFramerateLimit(60);
	window.setVerticalSyncEnabled(true);
	window.setMouseCursorVisible(false);

	sf::ContextSettings settings = window.getSettings();
	std::cout << "OpenGL version: " << settings.majorVersion << "." << settings.minorVersion << std::endl;
	std::cin.get();

	struct {
		double x;
		double y;
		double direction;
		sf::Texture texture;
		sf::Sprite sprite;
		sf::Text text;
		sf::Font font;
		sf::Vertex visibleAreaVertices[7];
	} arrow;

	arrow.x = 100;
	arrow.y = 100;
	arrow.direction = 0;
	arrow.visibleAreaVertices[0].color = sf::Color(0,0,0,100);
	for(int i = 1; i < 7; i++) { arrow.visibleAreaVertices[i].color = sf::Color(0,0,0,50); }

	arrow.texture.loadFromFile("images/arrow.png");
	arrow.texture.setSmooth(true);
	arrow.sprite.setTexture(arrow.texture);
	arrow.sprite.setOrigin(5,8);
	arrow.font.loadFromFile("data/OpenSans-Regular.ttf");
	arrow.text.setFont(arrow.font);
	arrow.text.setColor(sf::Color::Black);
	arrow.text.setCharacterSize(14);


	struct{
		sf::Texture texture;
		sf::Sprite sprite;
	} background;

	background.texture.loadFromFile("images/back.png");
	background.texture.setRepeated(true);
	background.sprite.setTexture(background.texture);
	background.sprite.setTextureRect(sf::IntRect(0,0,window.getSize().x, window.getSize().y));


	struct{
		sf::Image image;
		sf::Texture texture;
		sf::Sprite sprite;
	} obstacles;
	obstacles.image.loadFromFile("images/obstacles.png");
	obstacles.texture.loadFromImage(obstacles.image);
	obstacles.sprite.setTexture(obstacles.texture);


	struct{
		sf::RenderTexture renderTexture;
		sf::Sprite sprite;
	} scene;
	scene.renderTexture.create(window.getSize().x, window.getSize().y);
	scene.sprite.setTexture(scene.renderTexture.getTexture());


	struct{
		sf::RenderTexture renderTexture;
		sf::Sprite sprite;
		sf::Texture obstacleTexture;
		sf::Sprite obstacleSprite;
		sf::RectangleShape back;
	} shadow;
	shadow.back.setSize(sf::Vector2f(LIGHT_RADIUS * 2.f, LIGHT_RADIUS * 2.f));
	shadow.back.setOutlineColor(sf::Color::Black);
	shadow.back.setOutlineThickness(2);
	shadow.back.setFillColor(sf::Color::Black);
	shadow.back.setPosition(window.getSize().x - LIGHT_RADIUS * 2.f, 0.f);
	shadow.sprite.setTexture(shadow.renderTexture.getTexture());
	shadow.sprite.setTextureRect(sf::IntRect(0,0,LIGHT_RADIUS * 2, LIGHT_RADIUS * 2));
	shadow.obstacleSprite.setTexture(shadow.obstacleTexture);
	shadow.obstacleSprite.setTextureRect(sf::IntRect(0,0,LIGHT_RADIUS * 2, LIGHT_RADIUS * 2));
	shadow.obstacleSprite.setPosition(window.getSize().x - LIGHT_RADIUS * 2.f, 0.f);

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();

			if (event.type == sf::Event::MouseWheelMoved)
			{
				arrow.direction -= event.mouseWheel.delta * 0.1;
				if(arrow.direction < 0) arrow.direction += 2 * M_PI;
				else if(arrow.direction > 2 * M_PI) arrow.direction -= 2 * M_PI;
			}
        }

		sf::Vector2i mousePosition = sf::Mouse::getPosition(window);
		arrow.x = mousePosition.x;
		arrow.y = mousePosition.y;

		arrow.sprite.setPosition(arrow.x, arrow.y);
		arrow.sprite.setRotation(arrow.direction * 180.f / M_PI);
		char angleDisplay[16];
		sprintf_s(angleDisplay, "%.2f.PI rad", arrow.direction / M_PI);
		arrow.text.setString(angleDisplay);
		arrow.text.setPosition(arrow.x, arrow.y - 50);
		arrow.visibleAreaVertices[0].position = sf::Vector2f(arrow.x, arrow.y);
		for(int i = 1; i < 7; i++)
		{
			arrow.visibleAreaVertices[i].position = 
				sf::Vector2f(
				arrow.x + cos(LIGHT_FOCAL_ANGLE_RAD / 5.f * (i - 1.f) - LIGHT_FOCAL_ANGLE_RAD * 0.5f + arrow.direction) * 100.f, 
				arrow.y + sin(LIGHT_FOCAL_ANGLE_RAD / 5.f * (i - 1.f) - LIGHT_FOCAL_ANGLE_RAD * 0.5f + arrow.direction) * 100.f);
		}

		// obstacle map portion extraction
		if(!shadow.obstacleTexture.loadFromImage(obstacles.image, sf::IntRect(
			(int)arrow.x - LIGHT_RADIUS,
			(int)arrow.y - LIGHT_RADIUS,
			LIGHT_RADIUS * 2,
			LIGHT_RADIUS * 2
			)))
		{
			std::cerr << "error while loading obstaclesTextureExtract" << std::endl;
		}

		scene.renderTexture.clear(sf::Color::White);
		scene.renderTexture.draw(background.sprite);
		scene.renderTexture.draw(obstacles.sprite);
		scene.renderTexture.display();

		window.draw(scene.sprite);
		window.draw(shadow.back);
		window.draw(shadow.obstacleSprite);
		window.draw(arrow.visibleAreaVertices, 7, sf::TrianglesFan);
		window.draw(arrow.sprite);
		window.draw(arrow.text);

        window.display();
    }
}